﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;

namespace Common.Util
{
    ///<summary>
    ///</summary>
    public static class StringExtensions
    {
        /// <summary>
        /// constant
        /// </summary>
        private const string KEY_ARRAY_DEFAULT = "TUDD-COMMON.COM-MVC";

        /// <summary>
        /// This will get 4 characer at last of the string
        /// </summary> 
        /// <param name="source"></param>
        /// <returns></returns>
        public static string LastFour(this string source)
        {
            if (string.IsNullOrEmpty(source)) return string.Empty;
            if (source.Length < 4) return string.Empty;
            return source.Substring(source.Length - 4);
        }

        /// <summary>
        /// check isnull or empty of string
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static bool IsNullOrEmpty(this string value)
        {
            return string.IsNullOrEmpty(value);
        }

        /// <summary>
        /// check isnull or whitespace of string
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static bool IsNullOrWhiteSpace(this string value)
        {
            return string.IsNullOrWhiteSpace(value);
        }

        /// <summary>
        /// Endcode 2 dimentions
        /// </summary>
        /// <param name="toEncrypt"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static string Encode(this string toEncrypt, string key)
        {
            if (string.IsNullOrEmpty(key) && string.IsNullOrEmpty(toEncrypt)) return string.Empty;
            byte[] preKeyArray = KEY_ARRAY_DEFAULT.ToCharArray().Select(x => (byte)x).ToArray();
            byte[] keyArray;
            byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);
            MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
            keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(KEY_ARRAY_DEFAULT + key));
            Array.Resize<byte>(ref preKeyArray, keyArray.Length);
            keyArray.CopyTo(preKeyArray, preKeyArray.Length - keyArray.Length);

            TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
            tdes.Key = preKeyArray;
            tdes.Mode = CipherMode.ECB;
            tdes.Padding = PaddingMode.PKCS7;
            ICryptoTransform cTransform = tdes.CreateEncryptor();
            byte[] resultArray = cTransform.TransformFinalBlock(
                toEncryptArray, 0, toEncryptArray.Length);
            return Convert.ToBase64String(resultArray, 0, resultArray.Length);
        }

        /// <summary>
        /// Decode 2 dimentions
        /// </summary>
        /// <param name="toEncrypt"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static string Decode(this string toDecrypt, string key)
        {
            try
            {
                byte[] keyArray;
                byte[] toEncryptArray = Convert.FromBase64String(toDecrypt);
                byte[] preKeyArray = KEY_ARRAY_DEFAULT.ToCharArray().Select(x => (byte)x).ToArray();

                MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
                keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(KEY_ARRAY_DEFAULT + key));
                Array.Resize<byte>(ref preKeyArray, keyArray.Length);
                keyArray.CopyTo(preKeyArray, preKeyArray.Length - keyArray.Length);

                TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
                tdes.Key = preKeyArray;
                tdes.Mode = CipherMode.ECB;
                tdes.Padding = PaddingMode.PKCS7;

                if (toEncryptArray.Length == 0) return string.Empty;
                ICryptoTransform cTransform = tdes.CreateDecryptor();
                byte[] resultArray = cTransform.TransformFinalBlock(
                toEncryptArray, 0, toEncryptArray.Length);
                return UTF8Encoding.UTF8.GetString(resultArray);
            }
            catch
            {
                return string.Empty;
            }
        }

        /// <summary>
        /// ConvertToUnSign string
        /// </summary>
        /// <param name="text"></param>
        /// <returns></returns>
        public static string ToUnSign(this string text)
        {
            string result = string.Empty;
            Regex regex = new Regex(@"\p{IsCombiningDiacriticalMarks}+");
            string strFormD = (text + " ").Normalize(System.Text.NormalizationForm.FormD);
            result = regex.Replace(strFormD, String.Empty).Replace('\u0111', 'd').Replace('\u0110', 'D').ToUpper().Replace(" DO ", " WO ");
            if (result.StartsWith("DO ")) result = result.Replace("DO ", "WO ");
            if (result.EndsWith(" DO")) result = result.Replace(" DO", " WO");
            if (result.EndsWith(" ")) result = result.Remove(result.Length - 1);
            return result;
        }

        /// <summary>
        /// ConvertToSHAPassword
        /// </summary>
        /// <param name="text"></param>
        /// <returns></returns>
        public static string ToSHAPassword(this string text)
        {
            text = text + Encode(text, KEY_ARRAY_DEFAULT);
            byte[] bytes = Encoding.Unicode.GetBytes(text);
            System.Security.Cryptography.SHA256Managed hashstring = new System.Security.Cryptography.SHA256Managed();
            byte[] hash = hashstring.ComputeHash(bytes);
            string hashString = string.Empty;
            foreach (byte x in hash)
            {
                hashString += String.Format("{0:x2}", x);
            }

            return hashString;
        }

        /// <summary>
        /// Check string input is yes or not
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static bool IsYes(this string input)
        {
            if (input.IsNullOrWhiteSpace()) return false;
            input = input.ToUpper().Trim();
            if (input == "Y" || input == "YES" || input == "TRUE") return true;
            return false;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static bool? ToBoolean(this string input)
        {
            if (string.IsNullOrWhiteSpace(input)) return null;
            if (input.ToUpper() == BooleanString.FALSE)
                return false;
            if (input.ToUpper() == BooleanString.TRUE)
                return true;
            return null;
        }

        /// <summary>
        /// Convert to date time string
        /// </summary>
        /// <param name="dateString"></param>
        /// <param name="dateFormat"></param>
        /// <returns></returns>
        public static DateTime? ToDateTime(this string dateString, string dateFormat = "MM/dd/yyyy")
        {
            CultureInfo culture = CultureInfo.CurrentCulture;
            DateTime date = DateTime.MinValue;
            if (DateTime.TryParseExact(dateString, dateFormat, culture, System.Globalization.DateTimeStyles.None, out date))
                return date;

            return null;
        }

        /// <summary>
        /// convert to int value
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static int ToInt(this string input)
        {
            int intValue = int.MinValue;
            int.TryParse(input, out intValue);
            return intValue;
        }

        /// <summary>
        /// convert to  decima Number value
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static decimal ToNumber(this string input)
        {
            decimal intValue = decimal.MinValue;
            decimal.TryParse(input, out intValue);
            return intValue;
        }

        public static string AddCharsCapitalized(this string text, char splitChar)
        {
            if (string.IsNullOrWhiteSpace(text))
                return text;
            StringBuilder newText = new StringBuilder();
            newText.Append(text[0]);
            for (int i = 1; i < text.Length; i++)
            {
                if (char.IsUpper(text[i]) && text[i - 1] != splitChar)
                    newText.Append(splitChar);
                newText.Append(text[i]);
            }
            return newText.ToString();
        }

        private const string VERIFY_PATTEN = @"^((?:[\u005c\u003a\s\u005f\u002e]|[a-zA-Z0-9]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*{0}[0-9]+\.[jJ][pP][gG])$";
        public static string SaveVerifyCode(this string watermark, string pathSaved, string prefix = "VerifyNumber", bool clearHist = false)
        {
            if (!Directory.Exists(pathSaved))
            {
                return string.Empty;
            }

            Bitmap bitmap;
            Graphics g;

            // initialize the blank bitmap
            bitmap = new Bitmap(152, 70);
            g = Graphics.FromImage(bitmap);
            HatchBrush hb = new HatchBrush(HatchStyle.DottedGrid, Color.Black, Color.White);
            g.FillRectangle(hb, 0, 0, 152, 70);

            // Drawstring the transparent text to the Graphics context at x,y position.
            g.SmoothingMode = SmoothingMode.AntiAlias & SmoothingMode.HighQuality;
            //This is the font for your watermark
            Font myFont = new Font("Arial", 32, FontStyle.Bold);
            SolidBrush brush = new SolidBrush(Color.FromArgb(100, Color.Blue));

            //This gets the size of the graphic
            SizeF textSize = g.MeasureString(watermark, myFont);

            // Code for writing text on the image and showing its postion on images. 
            int X, Y;
            X = ((int)(bitmap.Width - textSize.Width) / 2);
            Y = ((int)(bitmap.Height - textSize.Height) / 2 + 5);
            PointF pointF = new PointF(X, Y);
            g.DrawString(watermark, myFont, brush, pointF);

            // initialize the CoolWatermark writer and assign the properties   
            //bitmap = new Bitmap(writer.WriteText(number.ToString()));
            //writer.Dispose();

            //Clear old file
            if (clearHist)
            {
                string[] file = System.IO.Directory.GetFiles(pathSaved);
                string pattent = string.Format(VERIFY_PATTEN, prefix);
                for (int i = 0; i < file.Length; i++)
                {
                    var fileCheck = file[i];
                    if (Regex.IsMatch(fileCheck, pattent))
                    {
                        File.Delete(fileCheck);
                    }
                }
            }

            string strFName = prefix + DateTime.Now.ToFileTime().ToString() + ".jpg";
            bitmap.Save(Path.Combine(pathSaved, strFName));
            bitmap.Dispose();
            g.Dispose();
            return strFName;
        }


        public static int ClearVerifyCode(this string pathSaved, string prefix = "VerifyNumber")
        {
            if (!Directory.Exists(pathSaved))
            {
                return -1;
            }

            //Clear old file 
            string[] file = System.IO.Directory.GetFiles(pathSaved);
            string pattent = string.Format(VERIFY_PATTEN, prefix);
            int result = 0;
            for (int i = 0; i < file.Length; i++)
            {
                var fileCheck = file[i];
                if (Regex.IsMatch(fileCheck, pattent))
                {
                    File.Delete(fileCheck);
                    result++;
                }
            }
            return result;
        }

        public static string CreateRandomPassword(int length)
        {
            const string valid = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890~!@#$%^&*()_+`-?/|\";
            StringBuilder res = new StringBuilder();
            Random rnd = new Random();
            while (0 < length--)
            {
                res.Append(valid[rnd.Next(valid.Length)]);
            }
            return res.ToString();
        }

        public static string NonUnicode(this string text)
        {
            string[] arr1 = new string[] { "á", "à", "ả", "ã", "ạ", "â", "ấ", "ầ", "ẩ", "ẫ", "ậ", "ă", "ắ", "ằ", "ẳ", "ẵ", "ặ",  
                                        "đ",  
                                        "é","è","ẻ","ẽ","ẹ","ê","ế","ề","ể","ễ","ệ",  
                                        "í","ì","ỉ","ĩ","ị",  
                                        "ó","ò","ỏ","õ","ọ","ô","ố","ồ","ổ","ỗ","ộ","ơ","ớ","ờ","ở","ỡ","ợ",  
                                        "ú","ù","ủ","ũ","ụ","ư","ứ","ừ","ử","ữ","ự",  
                                        "ý","ỳ","ỷ","ỹ","ỵ",};
            string[] arr2 = new string[] { "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", "a",  
                                        "d",  
                                        "e","e","e","e","e","e","e","e","e","e","e",  
                                        "i","i","i","i","i",  
                                        "o","o","o","o","o","o","o","o","o","o","o","o","o","o","o","o","o",  
                                        "u","u","u","u","u","u","u","u","u","u","u",  
                                        "y","y","y","y","y",};
            for (int i = 0; i < arr1.Length; i++)
            {
                text = text.Replace(arr1[i], arr2[i]);
                text = text.Replace(arr1[i].ToUpper(), arr2[i].ToUpper());
            }
            return text;
        }
    }
}
